# -*- coding: utf-8 -*-
# created on 2017/3/1

import re
from sympy import sympify
from mathsolver.functions.base import (BaseFunction, BaseFunc, BaseEq, BaseBelong, BaseSinFunc, BasePoly, BaseIneq,
                                       BaseVariable, BaseIneqs, BaseHengChenLi, BaseHypo, BaseFuncEq, new_latex,
                                       BaseFuncAssign)
from mathsolver.functions.daoshu.daoshuyunsuan import HanShuDaoShuYunSuan
from mathsolver.functions.fangcheng import FangChenBuDengShi002
from mathsolver.functions.hanshu.dingyiyu import QiuDingYiYu
from mathsolver.functions.hanshu.duicheng import zhouduicheng_dingyishi_general
from mathsolver.functions.hanshu.fanhanshu import HanShuInverse
from mathsolver.functions.hanshu.fenduan_jiebudengshi import FenDuanHanShuJieBuDengShi
from mathsolver.functions.hanshu.hengchengli import HengChengLiCunZaiXing
from mathsolver.functions.hanshu.jiaodian_duichengxing import JiaoDianDuiCheng
from mathsolver.functions.hanshu.jiou_dandiao_budengshi_new import _def_func
from mathsolver.functions.hanshu.jiou_dingyi import jiou_dingyishi_general
from mathsolver.functions.hanshu.jiou_jiajian import JiJiaJianOu
from mathsolver.functions.hanshu.jiou_qiujiexishi import JiOuJieXiShi
from mathsolver.functions.hanshu.proof_hanshu_budengshi import ProofHanShuBuDengShi
from mathsolver.functions.hanshu.zhiyu import HanShuZhiYu
from mathsolver.functions.hanshu.zhouqi import zhouqi_dingyishi_general
from mathsolver.functions.logic import MtHypo
from mathsolver.functions.process import ProcessExpression


class HanShuJiOuConvert(BaseFunction):
    def solver(self, *args):
        f_name, f_var = args[0].name, args[0].var
        f = sympify('%s(%s)' % (f_name, str(f_var)))
        expr, step = jiou_dingyishi_general(f, args[1])
        self.steps.append([step, ""])
        self.output.append(BaseFuncEq(expr.args))
        self.label.add("函数的奇偶性")
        return self


class HanShuZhouQiConvert(BaseFunction):
    def solver(self, *args):
        f_name, f_var = args[0].name, args[0].var
        f = sympify('%s(%s)' % (f_name, str(f_var)))
        expr, step = zhouqi_dingyishi_general(f, args[1].sympify())
        self.steps.append([step, ""])
        self.output.append(BaseFuncEq(expr.subs(sympify('n'), 1).args))
        self.label.add("函数的周期性")
        return self


class HanShuDuiChengConvert(BaseFunction):
    def solver(self, *args):
        f_name, f_var = args[0].name, args[0].var
        eq = args[1].sympify()
        assert str(eq[0]) == "x"
        f = sympify('%s(%s)' % (f_name, str(f_var)))
        expr, step = zhouduicheng_dingyishi_general(f, eq[1])
        self.steps.append([step, ""])
        self.output.append(BaseFuncEq(expr.subs(sympify('n'), 1).args))
        self.label.add("函数的对称性")
        return self


class FanHanShuUpdate(BaseFunction):
    def solver(self, *args):
        funcname, func = args[:2]
        if len(args) > 2:
            eq = args[2]
            assert str(eq.value[0]) == "y" and str(eq.value[1]) == "x"
        new_func = HanShuInverse().solver(func).output[0]
        new_func.name = funcname.name
        new_func.type = ""
        # new_func = BaseFunc({"var":new_func.var, "type":"", "name":funcname.name, "expression": new_func.expression})
        self.output.append(new_func)
        return self


class PieceWiseUpdate(BaseFunction):
    def solver(self, *args):
        piecewise = args[0]
        cond, func = args[0].value
        if '\\u2208' in cond or '∈' in cond:
            piecewise.interval = BaseBelong(cond).interval
        else:
            piecewise.interval = list(FangChenBuDengShi002().solver(BaseIneqs(cond)).output[0].value.values())[0]
        piecewise.var = sympify(func["var"])
        piecewise.expression = sympify(func["expression"])
        self.output.append(piecewise)
        return self


class AssumeFunc(BaseFunction):
    def solver(self, *args):
        interval, funcname, funcassign, text = args
        f = _def_func(text, interval.interval, text,
                      f_io=[sympify(funcassign.value["var"]), sympify(funcassign.value["expression"])])
        self.output.append(BaseFunc({"var": funcname.var, "type": "", "name": funcname.name, "expression": f}))
        return self


class JiaoDianDuiChengSum(BaseFunction):
    def solver(self, *args):
        func, sum_ = args[:2]
        assert self.known['func_equations']
        stepsolver = JiaoDianDuiCheng().solver(func, self.known['func_equations'][0], sum_.sympify())
        return stepsolver


class ComputeLimit(BaseFunction):
    def solver(self, *args):
        value = args[0].doit()
        self.steps.append(["%s = %s" % (new_latex(args[0]), new_latex(value)), ""])
        return self


class TofFuncXiangTong(BaseFunction):
    def solver(self, *args):
        dingyiyu1 = QiuDingYiYu().solver(args[0])
        dingyiyu2 = QiuDingYiYu().solver(args[1])
        if str(dingyiyu1) != str(dingyiyu2):
            self.output.append(BaseVariable(False))
        else:
            zhiyu1 = HanShuZhiYu().solver(args[0]).output[0].value
            zhiyu2 = HanShuZhiYu().solver(args[1]).output[0].value
            if str(zhiyu1) != str(zhiyu2):
                self.output.append(BaseVariable(False))
            else:
                self.output.append(BaseVariable(True))
        return self


class ProcessFuncAssign(BaseFunction):
    def solver(self, *args):
        func = self.search(args[0].value["name"])
        if func and isinstance(func, (BaseSinFunc, BaseFunc)):
            try:
                f2 = args[0].value["expression"]
                f1 = ProcessExpression(known=self.known).solver(
                    BasePoly("%s(%s)" % (args[0].value["name"], args[0].value["var"]))).output[0].value
                self.output.append(BaseEq([f1, f2]))
                return self
            except Exception:
                pass
        elif isinstance(args[0], BaseFuncAssign):
            func = args[0]
            print(1)
            pass

        self.output.append(args[0])
        return self


class ProcessFuncEq(BaseFunction):
    def solver(self, *args):
        try:
            f1, f2 = args[0].value
            if re.match("[fgh]\\(x\\)$", str(f1)):
                stepsolver = ProcessExpression(known=self.known).solver(BasePoly(f2))
                self.output.append(
                    BaseFunc({"name": f1[0], "type": "", "var": "x", "expression": stepsolver.output[0].value}))
            else:
                stepsolver = ProcessExpression(known=self.known).solver(args[0])
                return stepsolver
        except Exception:
            if self.known["func_equations"]:
                try:
                    stepsolver = JiJiaJianOu(known=self.known).solver(self.known["func_equations"], args[0])
                    return stepsolver
                except Exception:
                    pass

        self.output.extend(args)
        return self


class ProofExpression(BaseFunction):
    def solver(self, *args):
        ineq = ProcessExpression(known=self.known).solver(args[0]).output[0]
        if self.known["inequations"]:
            return ProofHanShuBuDengShi().solver(BaseIneqs(self.known["inequations"]), ineq)
        else:
            return ProofHanShuBuDengShi().solver(ineq)


class FuncProve(BaseFunction):
    def solver(self, *args):
        assert len(args[0].free_symbols()) == 1
        if self.known["inequations"]:
            return ProofHanShuBuDengShi().solver(BaseIneqs(self.known["inequations"]), args[0])
        else:
            return ProofHanShuBuDengShi().solver(args[0])


class ExpFuncUpdate(BaseFunction):
    def solver(self, *args):
        value = args[0].value
        value["expression"] = "x**kk"
        self.output.append(BaseFunc(value))
        return self


class HanShuUpdateDingYiYu(BaseFunction):
    def solver(self, *args):
        func = args[1]
        func.dingyiyu = args[0].interval
        self.output.append(func)
        return self


class FuncDUpdate(BaseFunction):
    def solver(self, *args):
        new_func = HanShuDaoShuYunSuan().solver(args[0]).output[0]
        new_func.name = args[1].name
        self.output.append(new_func)
        return self


class FenDuanFuncBuDengShi(BaseFunction):
    def solver(self, *args):
        assert self.known['func_piecewise'] and self.known['func_equations']
        piecewise = self.known["func_piecewise"][0]
        expression = args[0].value
        for op in ["<=", ">=", "!=", "<", ">"]:
            if op in expression:
                item = expression.split(op)
                item = [item[0], op, item[1]]
                break

        piecefunc = JiOuJieXiShi().solver(self.known['func_equations'][0], piecewise[0], BaseFunc(
            {"name": "f", "type": "", "expression": piecewise[2], "var": "x"})).output[0]
        return FenDuanHanShuJieBuDengShi().solver(piecefunc, BaseIneq(item))


class HengChengLiExtra001(BaseFunction):
    def solver(self, *args):
        return HengChengLiCunZaiXing().solver(args[0], BaseBelong(["x", "\\in", args[1].interval]))


class HengChengLiCondition(BaseFunction):
    def solver(self, *args):
        expression, condition = args[:2]
        if isinstance(condition, BaseHypo):
            condition = MtHypo().classify(condition.value["condition"])
            expr = ProcessExpression(known=self.known).solver(expression).output[0]
            if condition.value["flag"] == "forall":
                self.output.append(expr)
                self.output.append(condition)
            else:
                raise ValueError()
        else:
            text = args[2]
            if "存在" in text:
                self.output.append(
                    BaseHypo({"flag": "exist", "condition": condition.value, "hypo": expression.value, "name": ""}))
            else:
                raise ValueError()
        return self


class JiZhiIsVariable(BaseFunction):
    def solver(self, *args):
        value, variable = args[:2]
        if isinstance(value.value, dict):
            key, item = list(value.value.items())[0]
            assert len(item) == 1
            value = item[0][1]
        elif isinstance(value.value, list):
            value = value.value[0]
        self.output.append(BaseEq([variable.sympify(), value]))
        return self


class HengChengLiUpdate(BaseFunction):
    def solver(self, *args):
        self.output.append(BaseHengChenLi(args[0].value))
        return self


if __name__ == '__main__':
    pass
